package sk.ogame.brain;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import sk.ogame.brain.thing.Thing;
import sk.ogame.brain.thing.ThingService;
import sk.ogame.brain.thing.WaitThing;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author 支绍昆
 * 2023/2/17
 * 主宰
 * 非线程安全
 **/
@Service
public class Overmind implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(Overmind.class);
    private static final Map<Class<? extends ThingService>, Object> beanMap = new HashMap<>();
    private static final List<Thing> thingList = new ArrayList<>(100);
    private static final List<Thing> swapList = new ArrayList<>(50);
    private static final AtomicBoolean change = new AtomicBoolean(false);
    private static final AtomicBoolean running = new AtomicBoolean(false);
    private boolean clearTag = false;

    @Autowired
    private ApplicationContext application;

    @Override
    public void run(String... args) {
        if (running.get()) {
            return;
        }
        if (running.compareAndSet(false, true)) {
            try {
                addSwap();
                //主宰启动
                Thread overmind = new Thread(this::scanAndDoThing);
                overmind.setName("◕_◕");
                overmind.start();
            } finally {
                running.set(false);
            }
        }
    }

    private void scanAndDoThing() {
        int count = 0;
        while (!thingList.isEmpty()) {

            if (clearTag){
                thingList.clear();
                this.clearTag = false;
            }

            logger.info("--------------------------------------------{}--------------------------------------------", count);
            change.set(false);
            int index = 0;
            while (index < thingList.size()) {
                try {
                    if (skip(thingList.get(index))) {
                        logger.info("skip thing [{}]", index);
                        index++;
                    } else {
                        doThing(index);
                    }
                } catch (Exception e) {
                    logger.info(e.getMessage());
                    dealException(e, index);
                    index++;
                }
            }
            logger.info("--------------------------------------------{}--------------------------------------------", count);
            count++;

            addSwap();
            thingList.sort(Comparator.comparing(Thing::getTime));
            if (!change.get()) {
                sleep(30);
            }
        }
    }

    private boolean skip(Thing thing) {
        if (thing instanceof WaitThing) {
            WaitThing wait = (WaitThing) thing;
            if (wait.getTimeStamp() > System.currentTimeMillis()) {
                return true;
            }
        }
        if (Objects.nonNull(thing.getPreThings())) {
            return true;
        }
        return false;
    }

    private void doThing(int index) {
        Thing thing = thingList.get(index);
        logger.info("deal thing [{}] : {}", index, thing);

        //获取可办理事情的bean.
        Class<? extends ThingService> beanType = thing.getDealBeanType();
        if (!beanMap.containsKey(beanType)) {
            Object bean = application.getBean(beanType);
            beanMap.put(beanType, bean);
        }
        //办理
        Thing newThing = ((ThingService) beanMap.get(beanType)).dealThing(thing);
        logger.info("remove  thing << [{}]", index);
        thingList.remove(index);

        //如果新的事情
        if (Objects.nonNull(newThing)) {
            newThing.setTime(thing.getTime() - 1);
            logger.info("add new thing >> [{}] : {}", index, newThing);
            thingList.add(index, newThing);
            if (Objects.nonNull(thing.getSuperior())) {
                Thing superior = thing.getSuperior();
                superior.setPreThings(newThing);
                newThing.setSuperior(superior);
            }
        } else if (Objects.nonNull(thing.getSuperior())) {
            thing.getSuperior().setPreThings(null);
        }

        //清理引用
        thing.setSuperior(null);
        thing.setPreThings(null);
        change.set(true);
    }

    private void dealException(Exception e, int index) {
        Thing newThing = ExceptionMind.deal(e);
        if (Objects.nonNull(newThing)) {
            //处理问题的事情
            Thing currentThing = thingList.get(index);
            newThing.setTime(currentThing.getTime() - 1);
            currentThing.setPreThings(newThing);
            newThing.setSuperior(currentThing);
            logger.info("add new thing >> [{}] : {}", index + 1, newThing);
            thingList.add(index + 1, newThing);
            change.set(true);
        }
    }

    private void addSwap() {
        if (swapList.isEmpty()) {
            return;
        }
        thingList.addAll(swapList);
        synchronized (swapList) {
            swapList.clear();
        }
    }

    private void sleep(int second) {
        logger.info("sleep {} second", second);
        try {
            Thread.sleep(1000L * second);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    //----------------------------------- out manager --------------------------------------

    public void add(Thing thing){
        synchronized (swapList){
            swapList.add(thing);
        }
        this.run();
    }

    public void clear(){
        this.clearTag = true;
    }

}
